<chapter xml:id="string_buffer.h">
<title><tt>__vic/string_buffer.h</tt></title>

<chapter xml:id="string_buffer">
<title><tt>string_buffer</tt></title>

<code-block lang="C++"><![CDATA[
class string_buffer : public std::string
{
public:
    string_buffer();
    explicit string_buffer(size_type n);
    string_buffer(const char *str);
    string_buffer(std::string str);
    string_buffer(string_ref sr);
    string_buffer(const std::string &str, size_type off, size_type n = npos);
    string_buffer(const char *char_buf, size_type n);
    string_buffer(const char *begin, const char *end);
    template<class InputIterator>
    string_buffer(InputIterator begin, InputIterator end);

    template<class T> string_buffer &operator<<(const T &v);

    string_buffer &operator=(string_ref sr);
    string_buffer &operator+=(string_ref sr);
    string_buffer &assign(string_ref sr);
    string_buffer &append(string_ref sr);

    // improved std::string calls
    string_buffer &assign(const std::string &str,
                            size_type off, size_type n = npos);
    string_buffer &append(const std::string &str,
                            size_type off, size_type n = npos);
    string_buffer &insert(size_type pos, const std::string &str,
                            size_type off, size_type n = npos);

    string_buffer &reserve(size_type n);
    string_buffer &clear();

    // missing container interface of std::string
    reference front();
    reference back();
    const_reference front() const;
    const_reference back() const;
    void pop_back();

    operator const char *() const;
};

string_buffer operator+(const string_buffer &s1, const string_buffer &s2);
string_buffer operator+(const string_buffer &s1, const std::string &s2);
string_buffer operator+(const std::string &s1, const string_buffer &s2);

string_buffer operator+(const string_buffer &s1, const char *s2);
string_buffer operator+(const char *s1, const string_buffer &s2);

string_buffer operator+(const string_buffer &s, char ch);
string_buffer operator+(char ch, const string_buffer &s);

using msg = string_buffer;
]]></code-block>

<p>Класс является улучшенным и расширенным <tt>std::string</tt>. Он имеет
следующие преимущества:</p>

<list style="numbered">

<item>Лево-ассоциативная операция конкатенации (<tt>&lt;&lt;</tt>),
позволяющая конструкции, вроде:
<code-block lang="C++"><![CDATA[
str << "Error message: " << err_msg << "\n";
]]></code-block></item>

<item>В конструкторе можно зарезервировать место под строку в целях
оптимизации, чтобы избежать многократного перераспределения буфера, что
значительно улучшает производительность. Часто имеется возможность оценить
максимальный размер строки. Но если она вдруг окажется длиннее, то буфер
автоматически расширится, как и у <tt>std::string</tt>.
<code-block lang="C++">
__vic::string_buffer st(4096);

// Эффект аналогичен
std::string st;
st.reserve(4096);
</code-block></item>

<item>Оператор <tt>&lt;&lt;</tt> воспринимает все фундаментальные типы:
числа, символы, указатели, <tt>bool</tt> и другие типы, к которым применима
<xref to="to_text_append"/>.
<code-block lang="C++"><![CDATA[
for(int i=0; i<10; i++)
    str << "i = " << i << '\n';
]]></code-block></item>

<item>Все операции, работающие с <tt>const char *</tt>, корректно воспринимают
пустой указатель как пустую строку. Реализации <tt>std::string</tt> не
проверяют указатель на пустоту и пытаются читать по нему в любом случае.
<code-block lang="C++">
std::string s1("Str");
const char *p = nullptr;
s1.append(p); // Oops.... Null pointer access!

__vic::string_buffer s2("Str");
s2.append(p); // Ok. s2 == "Str" still
s2 = p; // Ok. s2.empty() == true
</code-block></item>

<item>Автоматическое преобразование в <tt>const char *</tt> позволяет
использовать объекты в контекстах, требующих C-строку без явного преобразования.
<code-block lang="C++">
std::string fname(...);
FILE *fp = fopen(fname.c_str(), "r");

__vic::string_buffer fname(...);
FILE *fp = fopen(fname, "r");)
</code-block></item>

<item>Исправлены нерегулярности в дизайне класса <tt>std::string</tt>. Например,
класс является полноценным контейнером с доступом к его началу и концу, но у
него отсутствуют операции <tt>front()</tt> и <tt>back()</tt> в C++98.
Также класс имеет операцию <tt>push_back()</tt>, но не имеет симметричной
<tt>pop_back()</tt>.</item>

</list>

<p>При всех этих улучшениях, объекты данного типа полностью совместимы по
структуре с <tt>std::string</tt> и могут передаваться в контексты, требующие
<tt>std::string</tt>. Никаких дополнительных членов-данных в классе нет.</p>

<p>Использование инсертера (оператора <tt>&lt;&lt;</tt>) данного класса –
это простейший способ преобразовать число или указатель в строку. Механизм,
конечно, не такой мощный, как использование <tt>std::ostringstream</tt>,
например нельзя задать основание системы счисления или форматирование, но зато
самый простой и эффективный. Для вывода диагностики, к примеру, обычно его
вполне достаточно.</p>

<p>Также для данного типа введён синоним <tt>msg</tt>, который удобно
использовать для конструирования составных сообщений на лету одним
выражением без введения дополнительных переменных:</p>

<code-block lang="C++"><![CDATA[
oresult res = db_open(db_name);
if(res != 0) throw __vic::exception(
    __vic::msg(64) << "Cannot open DB " << db_name << ". res = " << res
);
]]></code-block>

<p>Как  видно в примере, в конструктор в целях оптимизации передан максимальный
ожидаемый размер строки.</p>

<section><title>Члены класса</title>

<synopsis>
<prototype>string_buffer()</prototype>
<p>Создаёт пустую строку.</p>
<postcondition><tt>empty() == true</tt></postcondition>
</synopsis>

<synopsis>
<prototype>explicit string_buffer(size_type n)</prototype>
<p>Вызывает <tt>reserve(n)</tt>.</p>
<postcondition><tt>capacity() >= n</tt></postcondition>
</synopsis>

<synopsis>
<prototype>string_buffer(const char *str)</prototype>
<prototype>string_buffer(std::string str)</prototype>
<p>Создаёт копию <tt>str</tt>.</p>
</synopsis>

<synopsis>
<prototype>string_buffer(const std::string &amp;str, size_type off, size_type n = npos)</prototype>
<p>Создаёт копию подстроки <tt>str</tt>.</p>
</synopsis>

<synopsis>
<prototype>string_buffer(const char *char_buf, size_type n)</prototype>
<p>Создаёт строку из буфера и его длины.</p>
</synopsis>

<synopsis>
<prototype>string_buffer(string_ref sr)</prototype>
<prototype>string_buffer(const char *begin, const char *end)</prototype>
<prototype>template&lt;class InputIterator>
string_buffer(InputIterator begin, InputIterator end)</prototype>
<p>Создаёт строку из диапазона символов.</p>
</synopsis>

<synopsis>
<prototype>template&lt;class T> string_buffer &amp;operator&lt;&lt;(const T &amp;v)</prototype>
<p>Вызывает <tt>to_text_append(v, *this)</tt>.</p>
</synopsis>

<synopsis>
<prototype>string_buffer &amp;operator=(string_ref sr)</prototype>
<prototype>string_buffer &amp;operator+=(string_ref sr)</prototype>
<prototype>string_buffer &amp;assign(string_ref sr)</prototype>
<prototype>string_buffer &amp;append(string_ref sr)</prototype>
<p>Операции для <tt>string_ref</tt>.</p>
</synopsis>

<synopsis>
<prototype>string_buffer &amp;reserve(size_type n)</prototype>
<prototype>string_buffer &amp;clear()</prototype>
<p>Вызывают одноимённую операцию <tt>std::string</tt> и дополнительно возвращают
ссылку на себя, что позволяет использовать вызовы в составных выражениях.</p>
</synopsis>

<synopsis>
<prototype>reference front()</prototype>
<prototype>reference back()</prototype>
<prototype>const_reference front() const</prototype>
<prototype>const_reference back() const</prototype>
<prototype>void pop_back()</prototype>
<p>Недостающие операции интерфейса <tt>std::string</tt> в C++98.</p>
</synopsis>

<synopsis>
<prototype>operator const char *() const</prototype>
<p>Вызывает <tt>std::string::c_str()</tt>.</p>
</synopsis>

<synopsis>
<prototype>string_buffer operator+(const string_buffer &amp;s1, const string_buffer &amp;s2)</prototype>
<prototype>string_buffer operator+(const string_buffer &amp;s1, const std::string &amp;s2)</prototype>
<prototype>string_buffer operator+(const std::string &amp;s1, const string_buffer &amp;s2)</prototype>
<prototype>string_buffer operator+(const string_buffer &amp;s1, const char *s2)</prototype>
<prototype>string_buffer operator+(const char *s1, const string_buffer &amp;s2)</prototype>
<prototype>string_buffer operator+(const string_buffer &amp;s, char ch)</prototype>
<prototype>string_buffer operator+(char ch, const string_buffer &amp;s)</prototype>
<p>Конкатенация строк и символов.</p>
</synopsis>

</section>

</chapter>

</chapter>
